<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    /*
        1.实现Thenable接口
     */
    class MyThenable {
        then() {
        }
    }

    /*
        2.Promise.prototype.then()
            - 接收两个参数
                - onResolved 函数  
                    - 函数里面的第一个参数为上一个promise返回的结果
                - onRejected 函数
            - 会在resolve或者reject状态时执行
     */

    // 2.1 then的基本用法
    let p1 = new Promise((resolve, reject) => setTimeout(resolve, 3000, 'success'))
    let p2 = new Promise((resolve, reject) => setTimeout(reject, 4000, 'failure'))

    p1.then((value) => {
        console.log('value1', value)  // 执行了  value1 success
    }, (error) => {
        console.log('error1', error)
    })
    p2.then((value) => {
        console.log('value2', value)
    }, (error) => {
        console.log('error2', error)  // 执行了 error2 failure
    })


    // 2.2  then里面的参数
    let p2_2 = Promise.reject('bad')
    // 非函数处理程序会被默认忽略,不推荐
    p2_2.then('kj')
    // 不传入onResolved的规范写法
    console.log('p2_2', p2_2)

    // 如果调用then() 不传递任何值,则原样向后传
    let p2_3 = p2_2.then()
    p2_3.then(null, (err) => setTimeout(console.log, 0, '2.2.捕获错误', err))

    // 返回undefined的情况
    let pro = Promise.resolve('foo');
    let pro1 = pro.then(() => undefined)
    let pro2 = pro.then(() => {
    })
    let pro3 = pro.then(() => Promise.resolve())
    setTimeout(console.log, 0, 'pro1', pro1)  // Promise {<fulfilled>: undefined}
    setTimeout(console.log, 0, 'pro2', pro2)
    setTimeout(console.log, 0, 'pro3', pro3)

    // 如果有显示的返回值,则Promise.resolve()会包装这个值
    let pro4 = pro.then(() => 'bar')
    let pro5 = pro.then(() => Promise.resolve('bar'))
    setTimeout(console.log, 0, 'pro4', pro4)  // Promise {<fulfilled>: "bar"}
    setTimeout(console.log, 0, 'pro5', pro5)  // Promise {<fulfilled>: "bar"}

    // 抛出异常会返回拒绝的promise
    let pro6 = pro.then(() => {
        throw 'baz'
    })
    setTimeout(console.log, 0, 'pro6', pro6)  // Promise {<rejected>: "baz"}

    // 返回错误值不会触发上面的拒绝行为,而是吧错误对象包装
    let pro7 = pro.then(() => Error('foo'))
    setTimeout(console.log, 0, 'pro7', pro7)  // Promise {<fulfilled>: Error: foo

    // Promise.reject()同理

    // 3 Promise.prototype.catch()
    // 也返回promise
    // 相同于语法糖 调用它就相当于调用 Promise.prototype. then(null, onRejected)。

    /*
         4.Promise.prototype.finally()
             - 这个处理程序在期约转换为解决或拒绝状态时都会执行
             - 最后一定要执行,与状态无关
             - 返回一个新的promise
     */

    let pms = Promise.resolve(1);
    let pms2 = Promise.reject(2);
    let pms3 = pms.finally(() => 3)
    setTimeout(console.log, 0, 'pms', pms)  // Promise {<fulfilled>: 1}
    setTimeout(console.log, 0, 'pms2', pms2) // Promise {<fulfilled>: 2}
    setTimeout(console.log, 0, 'pms3', pms3) // Promise {<fulfilled>: 1}

    /*
        5.执行顺序,关系到微任务和宏任务
     */
    let p5_1 = new Promise(resolve => {
        console.log(1)
        resolve(2)
        console.log(3)
    })
    console.log(4)
    p5_1.then(() =>setTimeout(console.log,0,5)).finally(() => console.log(6))
    p5_1.then((value) =>console.log(value)).finally(() =>console.log(7))
    console.log(8)
    // fixme:搞清楚  finally是在哪里执行  
    // 预想结果为: 1 3 4 8 6 2 7 5
    // 实际的结果: 1 3 4 8 2 6 7 5
    
    
    
    
</script>
</body>
</html>